/******************************
 * 时间格式转换
******************************/

// 时间戳转换为时间格式
// d - 一个月中的第几天（从 01 到 31）
// D - 星期几的文本表示（用三个字母表示）
// j - 一个月中的第几天，不带前导零（1 到 31）
// l（'L' 的小写形式）- 星期几的完整的文本表示
// N - 星期几的 ISO-8601 数字格式表示（1 表示 Monday[星期一]，7 表示 Sunday[星期日]）
// S - 一个月中的第几天的英语序数后缀（2 个字符：st、nd、rd 或 th。与 j 搭配使用）
// w - 星期几的数字表示（0 表示 Sunday[星期日]，6 表示 Saturday[星期六]）
// z - 一年中的第几天（从 0 到 365）
// W - 用 ISO-8601 数字格式表示一年中的星期数字（每周从 Monday[星期一]开始）
// F - 月份的完整的文本表示（January[一月份] 到 December[十二月份]）
// m - 月份的数字表示（从 01 到 12）
// M - 月份的短文本表示（用三个字母表示）
// n - 月份的数字表示，不带前导零（1 到 12）
// t - 给定月份中包含的天数
// L - 是否是闰年（如果是闰年则为 1，否则为 0）
// o - ISO-8601 标准下的年份数字 ×
// Y - ISO-8601 标准下的年份数字
// y - 年份的两位数表示
// a - 小写形式表示：am 或 pm
// A - 大写形式表示：AM 或 PM
// g - 12 小时制，不带前导零（1 到 12）
// G - 24 小时制，不带前导零（0 到 23）
// h - 12 小时制，带前导零（01 到 12）
// H - 24 小时制，带前导零（00 到 23）
// i - 分，带前导零（00 到 59）
// e - 分，不带前导零（0 到 59）
// s - 秒，带前导零（00 到 59）
// c - 秒，不带前导零（0 到 59）
// u - 微秒
// I（i 的大写形式）- 日期是否是在夏令时（如果是夏令时则为 1，否则为 0）
/** 
 * 将时间戳转换为指定的时间模式
 * @param format {String} 要转换的目标格式
 * @param timestamp {Number} 待转换的时间戳（默认为当前之间戳）
 * 
 * @return {String} 返回目标格式的时间内容
 * 
 * @example date('Y-m-d H:m:s', 1577808000) => `2020-01-01 00:00:00`
 * 
 * @author Wed 494917128@qq.com
 */
function date(format: string, timestamp?: number): string {
	var d = new Date();
	timestamp && d.setTime(timestamp);

	var _D_list = ['Sun', 'Mon', 'Tue', 'Wed', 'Thur', 'Fri', 'Sat'],
		_l_list = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
		_F_list = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
		_M_list = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],

		_Y = d.getFullYear(),
		_m = d.getMonth() + 1,
		_d = d.getDate(),
		_H = d.getHours(),
		_i = d.getMinutes(),
		_s = d.getSeconds(),
		_u = d.getMilliseconds(),
		_w = d.getDay(),

		_format = {
			'd': setTimeStart(_d),
			'D': _D_list[_w],
			'j': _d,
			'l': _l_list[_w],
			'N': _w === 0 ? 7 : _w,
			'S': setDayEnd(_d),
			'w': _w,
			'z': getz(d),
			'W': getW(d),
			'F': _F_list[_m - 1],
			'm': setTimeStart(_m),
			'M': _M_list[_m - 1],
			'n': _m,
			't': getCountDays(d),
			'L': isLeapYear(_Y),
			'o': 'o',
			'Y': _Y,
			'y': _Y.toString().substr(_Y.toString().length - 2, 2),
			'a': _H < 12 ? 'am' : 'pm',
			'A': _H < 12 ? 'AM' : 'PM',
			'B': 'B',
			'g': _H < 12 ? _H : _H - 12,
			'G': _H,
			'h': setTimeStart(_H < 12 ? _H : _H - 12),
			'H': setTimeStart(_H),
			'i': setTimeStart(_i),
			'e': _i,
			's': setTimeStart(_s),
			'c': _s,
			'u': _u,
			'I': isDayLightTime(d),
			'O': 'O',
			'P': 'P',
			'T': 'T',
			'Z': 'Z',
			'r': 'r',
			'U': 'U',
		};

	function properties(obj) {
		var props = [];
		for (var p in obj) props.push(p);
		return props;
	}

	var regex = new RegExp(properties(_format).map(function (str) {
		return new String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
	}).join("|"), "g");
	format = format.replace(regex, function ($0) { return _format[$0]; });

	return format;
};

/** 
 * 1 => 01，时间个位数时前面加0
 */
const setTimeStart = (val: number | string): string =>
	val.toString().length === 1 ? '0' + val : val + '';

/** 
 * st,nd,rd,th
 */
const setDayEnd = (num: number): 'st' | 'nd' | 'rd' | 'th' =>
	(num === 1 || num === 21 || num === 31 ? 'st' :
		num === 2 || num === 22 ? 'nd' :
			num === 3 || num === 23 ? 'rd' : 'th');

/** 
 * 获取t是一年中的第几天
 */
function getz(d: Date): number {
	var y = d.getFullYear(),
		startDate = new Date(y, 0, 0).getTime();
	return Math.floor((d.getTime() - startDate) / 1000 / 60 / 60 / 24 - 1);
};

/** 
 * 获取t是一年中的第几个星期
 */
function getW(d) {
	var y = d.getFullYear(),
		startDate = new Date(y, 0, 0).getTime();
	return Math.floor((d - startDate) / 1000 / 60 / 60 / 24 / 7 + 1);
};

/** 
 * t - 给定月份中包含的天数
 */
function getCountDays(d: Date): number {
	/* 获取当前月份 */
	var curMonth = d.getMonth();
	/*  生成实际的月份: 由于curMonth会比实际月份小1, 故需加1 */
	d.setMonth(curMonth + 1);
	/* 将日期设置为0, 这里为什么要这样设置, 我不知道原因, 这是从网上学来的 */
	d.setDate(0);
	/* 返回当月的天数 */
	return d.getDate();
};

/** 
 * L - 是否是闰年（如果是闰年则为 1，否则为 0）
 */
const isLeapYear = (year: number): 0 | 1 =>
	year % 4 === 0 && year % 100 !== 0 || year % 400 === 0 ? 1 : 0;

/**
 * 判断一个时间是在东半球还是西半球
 */
const isEastEarthTime = (d: Date): boolean =>
	d.getTimezoneOffset() < 0;

/**
 * 判断一个时间是否在夏令时
 */
function isDayLightTime(d) {
	var start = new Date();
	//得到一年的开始时间
	start.setMonth(0);
	start.setDate(1);
	start.setHours(0);
	start.setMinutes(0);
	start.setSeconds(0);
	var middle = new Date(start.getTime());
	middle.setMonth(6);
	// 如果年始和年中时差相同，则认为此国家没有夏令时
	if ((middle.getTimezoneOffset() - start.getTimezoneOffset()) === 0) {
		return 0;
	}
	//判断当前用户在东半球还是西半球
	var margin = isEastEarthTime(d) ? start.getTimezoneOffset() : middle.getTimezoneOffset();
	if (d.getTimezoneOffset() === margin) {
		return 1;
	}
	return 0;
};

let api = { date }
window['_'] = Object.assign(window['_'] || {}, api)
export default api